package com.google.code.swingonfire.showcase.component.clock;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JCheckBox;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.event.ListSelectionEvent;

import com.google.code.eventsonfire.Events;
import com.google.code.eventsonfire.awt.AWTEvents;
import com.google.code.eventsonfire.swing.SwingEventHandler;
import com.google.code.eventsonfire.swing.SwingEvents;
import com.google.code.swingonfire.border.ShadowBorder;
import com.google.code.swingonfire.builder.JCheckBoxBuilder;
import com.google.code.swingonfire.builder.JLabelBuilder;
import com.google.code.swingonfire.builder.JListBuilder;
import com.google.code.swingonfire.component.JBorderPanel;
import com.google.code.swingonfire.component.clock.DefaultJClockModel;
import com.google.code.swingonfire.component.clock.JClock;
import com.google.code.swingonfire.component.clock.JClockBuilder;
import com.google.code.swingonfire.component.clock.JClockModel;
import com.google.code.swingonfire.layout.GBC;
import com.google.code.swingonfire.showcase.TitlePanel;
import com.google.code.swingonfire.utility.Utils;

public class JClockShowcase extends JPanel
{

    private static final long serialVersionUID = -8833413669568891529L;

    private static final Timer TIMER = new Timer(JClockShowcase.class.getSimpleName(), true);

    private static class TimeZoneEntry implements Comparable<TimeZoneEntry>
    {
        private final String name;
        private final TimeZone timeZone;

        public TimeZoneEntry(TimeZone timeZone)
        {
            super();

            name = timeZone.getDisplayName(false, TimeZone.LONG);

            this.timeZone = timeZone;
        }

        public String getName()
        {
            return name;
        }

        public TimeZone getTimeZone()
        {
            return timeZone;
        }

        @Override
        public int hashCode()
        {
            final int prime = 31;
            int result = 1;

            result = (prime * result) + ((name == null) ? 0 : name.hashCode());

            return result;
        }

        @Override
        public boolean equals(Object obj)
        {
            if (this == obj)
            {
                return true;
            }

            if (obj == null)
            {
                return false;
            }

            if (getClass() != obj.getClass())
            {
                return false;
            }

            TimeZoneEntry other = (TimeZoneEntry) obj;

            if (name == null)
            {
                if (other.name != null)
                {
                    return false;
                }
            }
            else if (!name.equals(other.name))
            {
                return false;
            }

            return true;
        }

        @Override
        public int compareTo(TimeZoneEntry o)
        {
            return Utils.dictionaryCompare(name, o.getName());
        }

        @Override
        public String toString()
        {
            return name;
        }

    }

    private final JClockModel editableClockModel = new DefaultJClockModel();
    private final JClock editableClock = new JClockBuilder(editableClockModel).build();
    private final JClock clonedClock = new JClockBuilder(editableClockModel).editable(false).build();

    private final JList timeZoneList = Events.bind(
        new JListBuilder().items(getTimeZones()).listener(SwingEvents.fireOnListSelection()).build(), this);
    private final JClockModel timeZoneClockModel = new DefaultJClockModel();
    private final JClock timeZoneClock = new JClockBuilder(timeZoneClockModel).editable(false).build();
    private final JCheckBox timeZoneAnimatedBox = Events.bind(
        new JCheckBoxBuilder().selected(true).text("Animation enabled").listener("animated", AWTEvents.fireOnAction())
            .opaque(false).build(), this);

    public JClockShowcase()
    {
        super(new BorderLayout());

        setOpaque(true);

        JPanel panel = new JPanel(new GridBagLayout());
        GBC panelGBC = new GBC(2, 2);
        panel.add(editableClock, panelGBC.weight(1, 2).fill());
        panel.add(clonedClock, panelGBC.next().weight(1, 2).fill());

        JPanel timeZonePanel = new JPanel(new GridBagLayout());
        timeZonePanel.setOpaque(true);
        timeZonePanel.setBackground(Color.WHITE);
        GBC timeZoneGBC = new GBC(2, 3);
        timeZonePanel.add(timeZoneClock, timeZoneGBC.span(1, 3).weight(1, 1).fill());
        timeZonePanel.add(new JLabelBuilder("Timezone:").labelFor(timeZoneList).build(), timeZoneGBC.next());
        timeZonePanel.add(new JScrollPane(timeZoneList), timeZoneGBC.next().weight(0, 1).fill());
        timeZonePanel.add(timeZoneAnimatedBox, timeZoneGBC.next());

        panel.add(new JBorderPanel(timeZonePanel, ShadowBorder.create()), panelGBC.next().weight(2, 1).fill().span(2));

        TIMER.scheduleAtFixedRate(new TimerTask()
        {
            @Override
            public void run()
            {
                Calendar calendar = (Calendar) timeZoneClockModel.getSelected().clone();

                calendar = (Calendar) timeZoneClock.getModel().getSelected().clone();

                calendar.setTime(new Date());

//                timeZoneClock.getModel().setSelected(calendar, true);

            }
        }, 1000, 1000);

        add(new JBorderPanel(new TitlePanel("JClock", "An internationalized clock with animation effects"),
            ShadowBorder.create()), BorderLayout.NORTH);
        add(panel, BorderLayout.CENTER);
    }

    @SwingEventHandler(event = ListSelectionEvent.class)
    public void onTimeZone()
    {
        TimeZoneEntry timeZoneEntry = (TimeZoneEntry) timeZoneList.getSelectedValue();
        JClockModel model = timeZoneClock.getModel();
        Calendar calendar = (Calendar) model.getSelected().clone();

        calendar.setTimeZone(timeZoneEntry.getTimeZone());

        model.setSelected(calendar, true);
    }

    @SwingEventHandler(event = ActionEvent.class, eachTag = "animated")
    public void onAnimated()
    {
        timeZoneClock.setAnimated(timeZoneAnimatedBox.isSelected());
    }

    private static List<TimeZoneEntry> getTimeZones()
    {
        Collection<TimeZoneEntry> entries = new HashSet<TimeZoneEntry>();
        String[] ids = TimeZone.getAvailableIDs();

        for (String id : ids)
        {
            entries.add(new TimeZoneEntry(TimeZone.getTimeZone(id)));
        }

        List<TimeZoneEntry> results = new ArrayList<TimeZoneEntry>(entries);

        Collections.sort(results);

        return results;
    }
}
